package com.neusoft.neuiotms.dcvm.task.cmdbSyn.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.neusoft.bizcore.cache.caching.CacheService;
import com.neusoft.bizcore.web.utils.JsonUtils;
import com.neusoft.neuiotms.dcvm.bean.AttrBean;
import com.neusoft.neuiotms.dcvm.bean.LocationCiBean;
import com.neusoft.neuiotms.dcvm.bean.StandardCiBean;
import com.neusoft.neuiotms.dcvm.service.AssetService;
import com.neusoft.neuiotms.dcvm.service.LocationService;
import com.neusoft.neuiotms.dcvm.task.cmdbSyn.constants.CmdbSynConstants;
import com.neusoft.neuiotms.dcvm.task.cmdbSyn.service.RackUCalcService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class RackUCalcServiceImpl implements RackUCalcService {
    @Autowired
    private LocationService locationService;
    @Autowired
    private AssetService cmdbMicroService;
    @Autowired
    private CacheService cacheService;

    @Override
    //@Scheduled(initialDelay = 10000, fixedDelay = 365 * 10 * 24 * 3600000)
    public void doCalc() {
        final StopWatch stopwatch = new StopWatch();
        stopwatch.start();
        final List<LocationCiBean> matchPark = this.getMatchPark();

        final List<String> postCodeList = matchPark.stream().map(it -> it.getCode()).collect(Collectors.toList());
        postCodeList.add(0, "IDC");

        RackUCalcServiceImpl.log.info("matchPark: {}", JsonUtils.pojoToJson(postCodeList));

        postCodeList.forEach(posCode -> {
            //            final String posCode = park.getCode();
            try {

                final String data =
                        "{\"code\":\"P18\",\"data\":[{\"code\":\"total\",\"name\":\"总U位\",\"value\":300,\"unit\":\"U\"},{\"code\":\"used\",\"name\":\"已用\",\"value\":100,\"unit\":\"U\"},{\"code\":\"empty\",\"name\":\"未用\",\"value\":200,\"unit\":\"U\"},{\"code\":\"percent\",\"name\":\"空间利用率\",\"value\":0.333,\"unit\":\"\"}]}";
                //组装位置集合
                final List<String> locationList = this.getLocationList(posCode);
                if ("IDC".equals(posCode)) {
                    locationList.add(0, posCode);
                }
                locationList.forEach(locationCode -> {
                    // 获取机柜
                    final List<StandardCiBean> matchJG = this.getMatchJG(locationCode);
                    int total = 0;
                    int used = 0;

                    for (final StandardCiBean r : matchJG) {
                        final List<AttrBean> attrs = r.getAttrs();
                        for (final AttrBean attr : attrs) {
                            if (attr.getKey().equals("uHeight")) {
                                final Object attrValue = attr.getValue();
                                total += attrValue == null ? 42 : Integer.valueOf(attrValue.toString());
                                break;
                            }
                        }
                        //柜内设备
                        final List<StandardCiBean> assets = this.cmdbMicroService.getAllCiByForeignInst("cabinet",
                                r.getCode());
                        for (final StandardCiBean asset : assets) {
                            final List<AttrBean> attrs2 = asset.getAttrs();
                            for (final AttrBean attr : attrs2) {
                                if (attr.getKey().equals("uHeight")) {
                                    final Object attrValue = attr.getValue();
                                    used += attrValue == null ? 0 : Integer.valueOf(attrValue.toString());
                                    break;
                                }
                            }

                        }

                    }
                    final int empty = total - used;
                    double percent = 0;
                    if (total != 0) {
                        percent = Double.valueOf(used) / Double.valueOf(total);
                        BigDecimal bd = new BigDecimal(String.valueOf(percent));
                        bd = bd.setScale(3, BigDecimal.ROUND_HALF_UP);
                        percent = bd.doubleValue();

                    }
                    final JSONObject dataJo = JSON.parseObject(data);
                    dataJo.put("code", locationCode);
                    final JSONArray inDataArray = dataJo.getJSONArray("data");
                    for (final Object inData : inDataArray) {
                        final JSONObject inDataJo = (JSONObject) inData;
                        if (inDataJo.getString("code").equals("total")) {
                            inDataJo.put("value", total);
                        } else if (inDataJo.getString("code").equals("used")) {
                            inDataJo.put("value", used);
                        } else if (inDataJo.getString("code").equals("empty")) {
                            inDataJo.put("value", empty);
                        } else if (inDataJo.getString("code").equals("percent")) {
                            inDataJo.put("value", percent);
                        }
                    }
                    if (this.cacheService.isInCache(CmdbSynConstants.LOCATION_U_CACHE_NAME, locationCode)) {
                        this.cacheService.remove(CmdbSynConstants.LOCATION_U_CACHE_NAME, locationCode);
                    }
                    this.cacheService.put(CmdbSynConstants.LOCATION_U_CACHE_NAME, locationCode, dataJo);
                    if (RackUCalcServiceImpl.log.isDebugEnabled()) {
                        RackUCalcServiceImpl.log.debug("定时计算位置U位:位置编码 {} u位使用情况{}", locationCode,
                                dataJo.toJSONString());
                    }

                });
            } catch (final Exception e) {
                e.printStackTrace();
                RackUCalcServiceImpl.log.error("数据中心U位使用情况定时计算异常:{}", e.getMessage());

            }

        });
        stopwatch.stop();
        RackUCalcServiceImpl.log.info("定时计算位置U:位耗时{}", stopwatch.getTotalTimeSeconds());
    }

    private List<LocationCiBean> getMatchPark() {
        //数据中心-机楼-层-房间-列-机柜
        //子类型属性sub_location_type：PARK-BUILD-ROOM-FLOOR-LIE

        List<LocationCiBean> deepLocationsByOne = this.locationService.getDeepLocationsByOne("IDC", 1);
        deepLocationsByOne =
                deepLocationsByOne
                        .stream().filter(
                                x -> x.getAttrs().stream()
                                        .anyMatch(s -> s.getKey().equals("sub_location_type")
                                                && s.getValue().toString().contains("PARK")))
                        .collect(Collectors.toList());

        return deepLocationsByOne;

    }

    private List<StandardCiBean> getMatchJG(final String PosCode) {
        //数据中心-机楼-层-房间-列-机柜
        //子类型属性sub_location_type：PARK-BUILD-ROOM-FLOOR-LIE
        final List<StandardCiBean> allMatchJG = new ArrayList<>();
        List<LocationCiBean> deepLocationsByOne = this.locationService.getDeepLocationsByOne(PosCode, 5);
        deepLocationsByOne =
                deepLocationsByOne.stream()
                        .filter(x -> x.getAttrs().stream().anyMatch(
                                s -> s.getKey().equals("sub_location_type") && s.getValue().toString().contains("LIE")))
                        .collect(Collectors.toList());
        deepLocationsByOne.forEach(item -> {
            final List<StandardCiBean> itemCiByForeignInst =
                    this.cmdbMicroService.getAllCiByCatetoriesAndForeign("CT_RACK", "location",
                            item.getCode());
            allMatchJG.addAll(itemCiByForeignInst);
        });
        if (RackUCalcServiceImpl.log.isDebugEnabled()) {
            RackUCalcServiceImpl.log.debug("定时计算位置U位:位置编码 {} 下机柜 {} ", PosCode,
                    String.join(",", allMatchJG.stream().map(StandardCiBean::getCode).collect(Collectors.toList())));
        }
        RackUCalcServiceImpl.log.info("定时计算位置U位:位置编码 {} 下机柜数量 {} ", PosCode,
                allMatchJG.size());

        return allMatchJG;

    }

    private List<String> getLocationList(final String PosCode) {
        final List<LocationCiBean> deepLocationsByOne = this.locationService.getDeepLocationsByOne(PosCode, 5);
        final List<String> locationList =
                deepLocationsByOne.stream()
                        .filter(x -> x.getAttrs().stream()
                                .anyMatch(s -> s.getKey().equals("sub_location_type")
                                        && (s.getValue().toString().contains("PARK")
                                                || s.getValue().toString().contains("FLOOR")
                                                || s.getValue().toString().contains("ROOM"))))
                        .map(LocationCiBean::getCode)
                        .collect(Collectors.toList());
        if (RackUCalcServiceImpl.log.isDebugEnabled()) {
            RackUCalcServiceImpl.log.debug("定时计算位置U位:数据中心 {} 层，房间位置编码 {} ", PosCode, String.join(",", locationList));
        }
        RackUCalcServiceImpl.log.info("定时计算位置U位:数据中心 {} 层，房间位置数量 {} ", PosCode, locationList.size());
        return locationList;
    }
}
